/**
 * Copyright 2011 Reinier Kip
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Tritone basically implements checkbox groups. The group parent and its
 * children are interdependent. Children checkboxes that represent the
 * same entity behave as one.
 *
 * Examples at http://www.reinierkip.nl/
 */
(function ($) {

	var TritoneGroup,
		Tritone,
		triboxes = {},
		OPACITY_INTERMEDIATE = 0.4;

	TritoneGroup = function (element) {
		var children, ids, group;

		this.element = element;
		this.element.click($.proxy(this.cycleChecked, this));

		this.name = element.attr('data-tt-group');
		children = $('input[name][type=checkbox][data-tt-group=' + this.name + ']:not([data-tt-parent])');
		ids = $.unique($.map(children, function (element) {
			return $(element).attr('data-tt-entity');
		}));

		this.boxes = [];
		group = this;
		$.each(ids, function () {
			group.boxes.push(Tritone.get(this));
		});

		$.each(this.boxes, function () {
			this.addGroup(group);
		});

		this.checked = this.element.attr('checked');
		if(this.checked) {
			$.each(this.boxes, function() {
				this.checked = true;
			});
		}
	};
	TritoneGroup.prototype.update = function (recurse) {
		var boxesChecked = 0,
			boxesTotal = this.boxes.length,
			intermediate,
			group = this;

		if (recurse === undefined) {
			recurse = true;
		}

		$.each(this.boxes, function () {
			boxesChecked += (this.checked ? 1 : 0);
		});
		
		this.checked = (boxesChecked > 0);
		intermediate = (boxesChecked > 0 && boxesChecked < boxesTotal);
		this.element.css('opacity', intermediate ? OPACITY_INTERMEDIATE : 1);
		this.element.attr('checked', this.checked);
		this.element.attr('value', intermediate ? 0 : 1);

		$.each(this.boxes, function () {
			var intermediate = (boxesChecked === boxesTotal);
			this.elements.filter('[data-tt-group="' + group.name + '"]').css('opacity', (intermediate ? OPACITY_INTERMEDIATE : 1));
			this.elements.attr('checked', this.checked);
			this.elements.attr('value', intermediate ? '0' : '1');

			if (recurse) {
				$.each(this.groups, function () {
					if (this.name !== group.name) {
						this.update(false);
					}
				});
			}
		});
	};
	TritoneGroup.prototype.setChecked = function (checked) {
		this.checked = checked;
		if (this.checked === false) {
			$.each(this.boxes, function () {
				this.setChecked(true);
			});
		} else {
			$.each(this.boxes, function () {
				this.setChecked(false);
			});
		}
	};
	TritoneGroup.prototype.cycleChecked = function (event) {
		this.checked = !this.checked;
		var group = this;
		$.each(this.boxes, function () {
			this.checked = group.checked;
		});
		this.update();
	};
	
	Tritone = function (id) {
		this.elements = $('[data-tt-entity="' + id + '"]');
		this.elements.data('$Tritone', this);
		this.elements.click($.proxy(this.cycleChecked, this));

		this.checked = this.elements[0].checked;

		this.groups = [];
	};
	Tritone.prototype.addGroup = function (group) {
		this.groups.push(group);
	};
	Tritone.prototype.cycleChecked = function () {
		this.checked = !this.checked;
		
		$.each(this.groups, function () {
			this.update();
		});
	};
	Tritone.prototype.isChecked = function () {
		return this.checked;
	};
	Tritone.prototype.setChecked = function (checked) {
		this.checked = checked;
	};

	Tritone.get = function (id) {
		if (!triboxes[id]) {
			triboxes[id] = new Tritone(id);
		}

		return triboxes[id];
	};

	$(function () {
		var i, ids, parents, groups;
		// Attach a tritone id if checkbox doesn't have one
		i = 0;
		$('input[name][type=checkbox][data-tt-group]:not([data-tt-entity])').each(function () {
			$(this).attr('data-tt-entity', 'tribox-' + i);
			i += 1;
		});

		// Get all tritone boxes with same id and create Tritonees for them
		ids = $.unique($.map($('input[name][type=checkbox][data-tt-group][data-tt-entity]:not([data-tt-parent])'), function (element) {
			return $(element).attr('data-tt-entity');
		}));
		$.each(ids, function (i, id) {
			var box = Tritone.get(id);
		});

		// Create TritoneGroups and update UI
		parents = $('input[name][type=checkbox][data-tt-group][data-tt-parent][data-tt-entity]');
		groups = [];
		parents.each(function () {
			var element = $(this);
			groups.push(new TritoneGroup(element));
		});
		$.each(groups, function () {
			this.update();
		});
	});

}(jQuery));